#include  "board.h"
#include  "TypeDef.h"
#include  "hal_avr.h"
#include  "hal_IO_Spi.h"
#include  "hal_int.h"



//----------------------------------------------------------------------------------
//  void halIOSpiInit(INT8U clockrate)
//
//  DESCRIPTION:
//    Initialize the MCU's IO for SPI communication
//  
//  ARGUMENTS:
//    clockrate   -  the IO SPI speed
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
void halIOSpiInit(INT8U clockrate)
{
    // Set up pins
    MCU_IO_INPUT(IO_SPI_MISO_PORT, IO_SPI_MISO_PIN);
    MCU_IO_OUTPUT(IO_SPI_MOSI_PORT, IO_SPI_MOSI_PIN, 0);
    MCU_IO_OUTPUT(IO_SPI_SCK_PORT,  IO_SPI_SCK_PIN, 0);
    MCU_IO_OUTPUT(IO_SPI_CSN_PORT, IO_SPI_CSN_PIN, 1);
}

//----------------------------------------------------------------------------------
//  void halIOSpiWrite(INT8U addr, const INT8U *buffer, INT16U length)
//
//  DESCRIPTION:
//    Write data to device, starting at internal device address "addr".
//    The device will increment the address internally for every new byte
//    that is written. For single byte write, set length to 1.
//
//  ARGUMENTS:
//    addr   -  The device register address 
//    data   -  The pointer to the data start address
//    length -  The data length
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
INT8U halIOSpiWrite(INT8U addr, const INT8U* data, INT16U length)
{
    INT16U i;
    INT8U rc;
    INT8U  s;

    HAL_INT_LOCK(s);
    
    HAL_IO_SPI_BEGIN;

    rc = halSpiBitbangOut(addr);
    for (i = 0; i < length; i++)
    {
        halSpiBitbangOut(data[i]);
    }

    HAL_IO_SPI_END;

    HAL_INT_UNLOCK(s);
    
    return(rc);

}

//----------------------------------------------------------------------------------
//  INT8U halIOSpiRead(INT8U addr, INT8U* data, INT16U length)
//
//  DESCRIPTION:
//    Read data from device, starting at internal device address "addr".
//    The device will increment the address internally for every new byte
//    that is read. Note that the master device needs to write a dummy byte
//    (in this case 0) for every new byte in order to generate the clock to
//    clock out the data. For single byte read, set length to 1.
//
//  ARGUMENTS:
//    addr   -  The device register address 
//    data   -  The pointer to the data start address
//    length -  The data length
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
INT8U halIOSpiRead(INT8U addr, INT8U* data, INT16U length)
{
    INT16U i;
    INT8U rc;
    INT8U  s;
    
    HAL_INT_LOCK(s);

    HAL_IO_SPI_BEGIN;

    rc = halSpiBitbangOut(addr);
    for (i = 0; i < length; i++)
    {
        data[i] = halSpiBitbangIn();
    }

    HAL_IO_SPI_END;

    HAL_INT_UNLOCK(s);
    
    return(rc);
}


//----------------------------------------------------------------------------------
//  INT8U halIOSpiStrobe(INT8U cmd)
//
//  DESCRIPTION:
//    Special write function, writing only one byte (cmd) to the device.
//
//  ARGUMENTS:
//    cmd    -  The device register commend 
//
//  RETURNS:
//    None
//----------------------------------------------------------------------------------
INT8U halIOSpiStrobe(INT8U cmd)
{
    INT8U rc;
    INT8U  s;

    HAL_INT_LOCK(s);

    HAL_IO_SPI_BEGIN;

    rc = halSpiBitbangOut(cmd);

    HAL_IO_SPI_END;

    HAL_INT_UNLOCK(s);
    return(rc);
}

//----------------------------------------------------------------------------------
//  INT8U halSpiBitbangOut(INT8U data)
//
//  DESCRIPTION:
//    Using IO SPI transmit 8bit data to SPI device ,  using SPI mode 0
//
//  ARGUMENTS: 
//    data   -  The data which transmit by IOSPI
//
//  RETURNS:
//    rc     -  The 8 bit data which SPI circle bit in MISO
//----------------------------------------------------------------------------------
INT8U halSpiBitbangOut(INT8U data)
{
    INT8U i;
    INT8U rc = 0;

    for(i = 8; i > 0; i--)
    {
        // clock low
        MCU_IO_CLR(IO_SPI_SCK_PORT, IO_SPI_SCK_PIN);

        if (data & 0x80)
            MCU_IO_SET(IO_SPI_MOSI_PORT, IO_SPI_MOSI_PIN);
        else
            MCU_IO_CLR(IO_SPI_MOSI_PORT, IO_SPI_MOSI_PIN);
        data <<= 1;
        
        // clock high
        MCU_IO_SET(IO_SPI_SCK_PORT, IO_SPI_SCK_PIN);
        
        rc <<= 1;
        if (HAL_IO_SPI_SOMI_VAL)
            rc |= 0x01;
    }

    // clock low
    MCU_IO_CLR(IO_SPI_SCK_PORT, IO_SPI_SCK_PIN);

    return(rc);
}

//----------------------------------------------------------------------------------
//  INT8U halSpiBitbangIn(void)
//
//  DESCRIPTION:
//    Using IO SPI read 8bit data from SPI device , using SPI mode 0
//
//  ARGUMENTS: 
//    None
//
//  RETURNS:
//    data     -  The 8 bit data which SPI circle bit in MISO
//----------------------------------------------------------------------------------
INT8U halSpiBitbangIn(void)
{
    INT8U i;
    INT8U data = 0;

    for(i = 8; i > 0; i--)
    {
        // clock high
        MCU_IO_SET(IO_SPI_SCK_PORT, IO_SPI_SCK_PIN);
                
        data <<= 1;
        if (HAL_IO_SPI_SOMI_VAL)
            data |= 0x01;
        
        // clock low
        MCU_IO_CLR(IO_SPI_SCK_PORT, IO_SPI_SCK_PIN);

    }

    return(data);
}